package com.example.my_helper;

//环形队列
public class RingBuffer {

    private int r_ptr;
    private int w_ptr;
    private int r_mirror;
    private int w_mirror;
    private byte[] buf;
    private int buf_len = 4096;

    public RingBuffer(){
        this.buf = new byte[buf_len];
        clear();
    }

    public RingBuffer(int buf_len){
        if(buf_len > 0)
            this.buf_len = buf_len;
        else
            this.buf_len = 1;
        this.buf = new byte[buf_len];
        clear();
    }

    public boolean put(byte b){
        if(!isFull()){
            buf[w_ptr++] = b;
            if(w_ptr == buf_len) {
                w_mirror ^= 1;
                w_ptr = 0;
            }
            return true;
        }
        return false;
    }

    public boolean put(byte b, int timeout){
        while (!put(b)){
            if(timeout == 0){
                return false;
            }else if(timeout > 0){
                timeout--;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

    public int get(){
        int b = -1;
        if(!isEmpty()){
            b = buf[r_ptr++] & 0xff;
            if(r_ptr == buf_len){
                r_mirror ^= 1;
                r_ptr = 0;
            }
            return b;
        }
        return b;
    }

    public int get(int timeout){
        while (isEmpty()){
            if(timeout == 0){
                return -1;
            }else if(timeout > 0){
                timeout--;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
                return -1;
            }
        }
        return get();
    }

    public int write(byte[] b, int offset, int len){
        for(int i = 0; i < len; i++){
            if(!put(b[offset+i])) {
                return i;
            }
        }
        return len;
    }

    public int write(byte[] b, int offset, int len, int timeout){
        for(int i = 0; i < len; i++){
            if(!put(b[offset+i], timeout)) {
                return i;
            }
        }
        return len;
    }

    public int read(byte[] b, int offset, int len){
        int bb;
        for(int i = 0; i < len; i++){
            bb = get();
            if(bb == -1){
                return i;
            }
            b[offset+i] = (byte) bb;
        }
        return len;
    }

    public int read(byte[] b, int offset, int len, int timeout){
        int bb;
        for(int i = 0; i < len; i++){
            bb = get(timeout);
            if(bb == -1){
                return i;
            }
            b[offset+i] = (byte) bb;
        }
        return len;
    }

    public void clear(){
        r_mirror = w_mirror = 0;
        r_ptr = w_ptr = 0;
    }

    public boolean isEmpty(){
        if(r_ptr == w_ptr && r_mirror == w_mirror){
            return true;
        }else{
            return false;
        }
    }

    public boolean isFull(){
        if(r_ptr == w_ptr && r_mirror != w_mirror){
            return true;
        }else{
            return false;
        }
    }

    public int getSize(){
        if(isEmpty()){
            return 0;
        }else if(isFull()){
            return buf_len;
        }else{
            if(w_ptr > r_ptr){
                return w_ptr - r_ptr;
            }else{
                return (buf_len - r_ptr) + w_ptr;
            }
        }
    }
}
